﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StockFinder.Model;

namespace StockFinder.Services.PriceAnalysis
{
    public class FlatBasePriceAnalyser : IPriceAnalyser
    {
        public PriceAnalysisResult RunAnalysis(IOrderedEnumerable<DailyPrice> prices)
        {
            /*
             * flat base occurs when last price is below at least 5 week high 
             * and the difference between high and low is less than 15%
             * */

            PriceAnalysisResult result = new PriceAnalysisResult();

            IEnumerable<WeeklyPrice> weeklyPrices = prices.AsWeeklyPrices();

            //flat base is at least 5 weeks long
            if (weeklyPrices.Count() >= 5)
            {
                IOrderedEnumerable<WeeklyPrice> orderedWeeklyPrices = weeklyPrices
                    .OrderByDescending(i => i.Year)
                    .ThenByDescending(i => i.WeekOfYear);

                #region Setup initial data

                decimal latestWeeklyHigh = orderedWeeklyPrices.ElementAt(0).GetWeeklyHigh();
                decimal maximumHigh = latestWeeklyHigh;
                decimal maximumLow = orderedWeeklyPrices.ElementAt(0).GetWeeklyLow();
                decimal depth = 0;
                int weekCount = 0;
                int baseLength = 0;

                #endregion

                #region Loop prices

                //loop prices
                foreach (WeeklyPrice weeklyPrice in orderedWeeklyPrices)
                {
                    DailyPrice lastPrice = prices.ElementAt(0);

                    result.BaseDepth = depth;
                    result.PreviousHigh = maximumHigh;
                    result.BaseLow = maximumLow;
                    result.DaysOfPrices = prices.Count();
                    result.BaseLength = baseLength;
                    result.MostRecentPriceDate = lastPrice.PriceDate;

                    decimal sma50 = prices.GetSimpleMovingAverage(50);

                    if (sma50 > 0)
                    {
                        decimal percentFromSMA50 = lastPrice.AdjustedClose - sma50;

                        percentFromSMA50 = (percentFromSMA50 / sma50) * 100;

                        result.PercentFrom50SMA = percentFromSMA50;
                    }      

                    //new week
                    weekCount++;

                    #region Validate week prices

                    //check not empty prices
                    if (weeklyPrice.GetWeeklyOpen() == 0)
                    {
                        break;
                    }

                    #endregion

                    #region Set week high and low

                    //do we have a new peak?
                    if (weeklyPrice.GetWeeklyHigh() > maximumHigh)
                    {
                        //yes
                        maximumHigh = weeklyPrice.GetWeeklyHigh();
                    }

                    //do we have a new low point?
                    if (weeklyPrice.GetWeeklyLow() < maximumLow)
                    {
                        //yes
                        maximumLow = weeklyPrice.GetWeeklyLow();
                    }

                    #endregion

                    #region Calculate the base depth

                    //calculate depth
                    depth = ((maximumHigh - maximumLow) / maximumHigh) * 100;

                    #endregion

                    #region Flat base check

                    //have we breached base depth?
                    if (depth > 15)
                    {
                        //yes so check base length
                        result.Succeeded = (baseLength > 5);

                        //depth level breached so quit loop
                        break;
                    }
                    else
                    {
                        //no so check if this week was a valid base start
                        if (weeklyPrice.GetWeeklyHigh() == maximumHigh)
                        {
                            //yes so determine new base length
                            baseLength = weekCount;
                        }                        

                        //go to next week in loop
                    }

                    #endregion                    
                }

                #endregion
            }
            else
            {
                result.Succeeded = false;
            }

            return result;
        }
    }
}
